package com.jweb.plugin.mybatis.proxy;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jweb.annotaion.JMCache;
import com.jweb.annotaion.JParam;
import com.jweb.annotaion.JTransaction;
import com.jweb.plugin.cache.CustomCache;
import com.jweb.plugin.mybatis.MybatisPlugin;
import com.jweb.util.FormatUtil;

/**
 * 本来打算用jdk动态代理，死磕了两周还是放弃了。 Transaction依赖于Cglib,如果不引入cglib,asm则无法执行事务
 */
public class AopMybatisTransactionHandler implements MethodInterceptor {
	private Object target;
	private Logger log = LoggerFactory.getLogger(AopMybatisTransactionHandler.class);

	/**
	 * 创建代理对象
	 * 
	 * @param target
	 * @return
	 */
	public Object getInstance(Object target) {
		this.target = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		// 回调方法
		enhancer.setCallback(this);
		// 创建代理对象
		return enhancer.create();
	}

	@Override
	public Object intercept(Object obj1, Method method, Object[] args, MethodProxy methodproxy) throws Throwable {
		Object ret = null;
		JMCache jmc = method.getAnnotation(JMCache.class);
		if (jmc != null) {
			String group = jmc.group();
			String key = jmc.key();
			String keyVal = key;
			Boolean empty = jmc.empty();
			if (!FormatUtil.isEmpty(key)) {
				Annotation[][] ano = method.getParameterAnnotations();
				for (int j = 0; j < ano.length; j++) {
					if (ano[j].length > 0) {
						JParam jp = (JParam) ano[j][0];
						if (key.equals(jp.value())) {
							keyVal = FormatUtil.toString(args[j]);
						}
					}
				}
			}
			if (!empty) {
				Object retC = CustomCache.get(group, keyVal);
				if (FormatUtil.isEmpty(retC)) {
					ret = excute(obj1, method, args, methodproxy);// >>>>>>>>>>>>执行操作<<<<<<<<<<<<
				} else {
					ret = retC;
				}
				if (!FormatUtil.isEmpty(ret)) {
					CustomCache.set(group, keyVal, ret);
				}
			} else {
				ret = excute(obj1, method, args, methodproxy);// >>>>>>>>>>>>执行操作<<<<<<<<<<<<
				CustomCache.remove(group, key);
			}
		} else {
			ret = excute(obj1, method, args, methodproxy);// >>>>>>>>>>>>执行操作<<<<<<<<<<<<
		}

		return ret;
	}

	private Object excute(Object obj1, Method method, Object[] args, MethodProxy methodproxy) throws Throwable {
		Object ret = null;
		if (method.isAnnotationPresent(JTransaction.class)) {// 并且 该方法添加了事务注解
			log.info(">>>This Server has open transactions");
			TransactionFactory transactionFactory = new JdbcTransactionFactory();
			SqlSession sqlSession = MybatisPlugin.getSqlSessionFactory().openSession();
			AopMybatisSqlSessionUtil.setSession(sqlSession); // 保存session
			Transaction newTransaction = transactionFactory.newTransaction(sqlSession.getConnection());
			try {
				ret = methodproxy.invokeSuper(obj1, args);
				newTransaction.commit();
				log.info(">>>This transactions was commit");
			} catch (Exception e) {
				log.error(">>>This transactions was rollback");
				newTransaction.rollback();
				e.printStackTrace();
				throw e; // 千万记得异常要往外抛！！！，，拦截器是方法的装饰类，不能改变他的业务轨迹。
			} finally {
				newTransaction.close();
				sqlSession.close();
				AopMybatisSqlSessionUtil.removeSession();// 删除Session
			}
		} else {
			ret = methodproxy.invokeSuper(obj1, args);
		}
		return ret;
	}

}
